/**
 * Project: apollo-base-dal
 * 
 * File Created at 2017年2月15日
 * 
 * Copyright 2015-2016 dx.com Croporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * DongXue software Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with dx.com.
 */
package com.dx.pf.dal.router.dataSource;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

import com.alibaba.druid.pool.DruidDataSource;
import com.dx.pf.dal.Logger;
import com.dx.pf.dal.conf.RelaxedPropertyResolver;

/** 
* @ClassName: DynamicDataSourceRegister 
* @Description:动态数据源注册
* 在spring中继承EnvironmentAware重写方法setEnvironment可以在工程启动时获取到系统环境变量和applcation配置中的变量
* @author wuzhenfang(wzfbj2008@163.com)
* @date 2017年2月15日 下午1:11:20 
* @version V1.0 
*/
public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {

	private final static Logger logger = Logger.getLogger(DynamicDataSourceRegister.class);

	//初始化大小、最小、最大
	private int initialSize;
	private int minIdle;
	private int maxActive;
	//配置获取连接等待超时的时间
	private long maxWait;
	//配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒
	private long timeBetweenEvictionRunsMillis;
	//配置一个连接在池中最小生存的时间，单位是毫秒
	private long minEvictableIdleTimeMillis;
	
	private String validationQuery;
	private boolean testWhileIdle;
	private boolean testOnBorrow;
	private boolean testOnReturn;
	// 打开PSCache，并且指定每个连接上PSCache的大小（Oracle使用)
	private boolean poolPreparedStatements;
	private int maxPoolPreparedStatementPerConnectionSize;
	//配置监控统计拦截的filters
	private String filters;

	private String connectionProperties;
	/** 全局类型转换器 */
	private ConversionService conversionService = new DefaultConversionService();
	/** 配置属性 */
	private PropertyValues dataSourcePropertyValues;
	/** 数据源 */
	private Map<String, DataSource> customDataSources = new HashMap<String, DataSource>();// 客户数据源
	/** 默认数据源 */
	private DataSource defaultDataSource;

	/**
	 * spring启动加载多数据源配置
	 * @param Environment 访问property属性，包含系统属性，环境变量和自定义的</br>
	 */
	@Override
	public void setEnvironment(Environment env) {
		initDruidProperties(env);// 初始化druid配置
		initDefaultDataSource(env);// 初始化默认数据库
		initCustomDataSources(env);// 初始其他数据
	}

	/**
	 * 属性转换器
	 * @param env
	 */
	private void initDruidProperties(Environment env) {
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "druid.");
		initialSize = Integer.parseInt(propertyResolver.getProperty("initialSize"));
		minIdle = Integer.parseInt(propertyResolver.getProperty("minIdle"));
		maxActive = Integer.parseInt(propertyResolver.getProperty("maxActive"));
		maxWait = Long.parseLong(propertyResolver.getProperty("initialSize"));
		timeBetweenEvictionRunsMillis = Long.parseLong(propertyResolver.getProperty("timeBetweenEvictionRunsMillis"));
		minEvictableIdleTimeMillis = Long.parseLong(propertyResolver.getProperty("minEvictableIdleTimeMillis"));
		validationQuery = propertyResolver.getProperty("validationQuery");
		testWhileIdle = Boolean.parseBoolean(propertyResolver.getProperty("testWhileIdle"));
		testOnBorrow = Boolean.parseBoolean(propertyResolver.getProperty("testOnBorrow"));
		testOnReturn = Boolean.parseBoolean(propertyResolver.getProperty("testOnReturn"));
		poolPreparedStatements = Boolean.parseBoolean(propertyResolver.getProperty("poolPreparedStatements"));
		maxPoolPreparedStatementPerConnectionSize = Integer.parseInt(propertyResolver.getProperty("maxPoolPreparedStatementPerConnectionSize"));
		filters = propertyResolver.getProperty("filters");
		connectionProperties = propertyResolver.getProperty("connectionProperties");
	}

	/**
	 * 初始化主数据源
	 */
	private void initDefaultDataSource(Environment env) {
		// 读取主数据源
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "master.datasource.");
		Map<String, Object> dsMap = new HashMap<>();
		dsMap.put("type", propertyResolver.getProperty("type"));
		dsMap.put("driver-class-name", propertyResolver.getProperty("driver-class-name"));
		dsMap.put("url", propertyResolver.getProperty("url"));
		dsMap.put("username", propertyResolver.getProperty("username"));
		dsMap.put("password", propertyResolver.getProperty("password"));

		defaultDataSource = buildDataSource(dsMap); //创建数据源;

		dataBinder(defaultDataSource, env);
	}
	
	/**
	 * 初始化更多数据源
	 */
	private void initCustomDataSources(Environment env) {
		// 读取配置文件获取更多数据源，也可以通过defaultDataSource读取数据库获取更多数据源
		RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "slave.datasource.");
		String dsPrefixs = propertyResolver.getProperty("names");
		for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
			Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
			DataSource ds = buildDataSource(dsMap);
			customDataSources.put(dsPrefix, ds);
			dataBinder(ds, env);
		}
	}
	
	/**
	 * ImportBeanDefinitionRegistrar的作用是在运行时自动添加Bean到已有的配置类
	 * @param arg0 AnnotationMetadata参数用来获得当前配置类上的注解；
	 * @param registry BeanDefinittionRegistry参数用来注册Bean
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata arg0, BeanDefinitionRegistry registry) {
		Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
		// 将主数据源添加到更多数据源中
		targetDataSources.put("dataSource", defaultDataSource);
		DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
		// 添加更多数据源
		targetDataSources.putAll(customDataSources);
		for (String key : customDataSources.keySet()) {
			DynamicDataSourceContextHolder.dataSourceIds.add(key);
		}
		// 创建DynamicDataSource
		GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
		beanDefinition.setBeanClass(DynamicDataSource.class);
		beanDefinition.setSynthetic(true);
		MutablePropertyValues mpv = beanDefinition.getPropertyValues();
		//添加属性：AbstractRoutingDataSource.defaultTargetDataSource
		mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
		mpv.addPropertyValue("targetDataSources", targetDataSources);
		registry.registerBeanDefinition("dataSource", beanDefinition);//
		logger.info("Dynamic DataSource Registry");
	}

	/**
	 * 创建DataSource
	 * @param dsMap 数据源配置参数
	 * @return
	 */
	public DataSource buildDataSource(Map<String, Object> dsMap) {
		String driverClassName = dsMap.get("driver-class-name").toString();
		String url = dsMap.get("url").toString();
		String username = dsMap.get("username").toString();
		String password = dsMap.get("password").toString();

		DruidDataSource druidDataSource = new DruidDataSource();
		druidDataSource.setDriverClassName(driverClassName);
		druidDataSource.setUrl(url);
		druidDataSource.setUsername(username);
		druidDataSource.setPassword(password);

		druidDataSource.setInitialSize(initialSize);
		druidDataSource.setMinIdle(minIdle);
		druidDataSource.setMaxActive(maxActive);
		druidDataSource.setMaxWait(maxWait);
		druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
		druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
		druidDataSource.setValidationQuery(validationQuery);
		druidDataSource.setTestWhileIdle(testWhileIdle);
		druidDataSource.setTestOnBorrow(testOnBorrow);
		druidDataSource.setTestOnReturn(testOnReturn);
		druidDataSource.setPoolPreparedStatements(poolPreparedStatements);
		druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
		druidDataSource.setConnectionProperties(connectionProperties);
		try {
			druidDataSource.setFilters(filters);
			druidDataSource.init();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return druidDataSource;
	}

	/**
	 * 为DataSource绑定更多数据
	 * @param dataSource
	 * @param env
	 */
	private void dataBinder(DataSource dataSource, Environment env) {
//		RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
//		dataBinder.setConversionService(conversionService);
//		dataBinder.setIgnoreNestedProperties(false);// false
//		dataBinder.setIgnoreInvalidFields(false);// false
//		dataBinder.setIgnoreUnknownFields(true);// true
//		if (dataSourcePropertyValues == null) {
//			Map<String, Object> rpr = new RelaxedPropertyResolver(env, "master.datasource").getSubProperties(".");
//			Map<String, Object> values = new HashMap<String, Object>(rpr);
//			//排除已经设置的属性
//			values.remove("type");
//			values.remove("driver-class-name");
//			values.remove("url");
//			values.remove("username");
//			values.remove("password");
//			dataSourcePropertyValues = new MutablePropertyValues(values);
//		}
//		dataBinder.bind(dataSourcePropertyValues);
	}

	public static void main(String[] args) {
		
	}
}
